package com.hang.gymmanager.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hang.gymmanager.Enum.*;
import com.hang.gymmanager.common.BasePageReq;
import com.hang.gymmanager.convert.PojoConvert;
import com.hang.gymmanager.dto.TimePeriodDto;
import com.hang.gymmanager.entity.*;
import com.hang.gymmanager.exception.BusinessException;
import com.hang.gymmanager.mapper.ActivityMapper;
import com.hang.gymmanager.mapper.OrderMapper;
import com.hang.gymmanager.mapper.SeatMapper;
import com.hang.gymmanager.mapper.WalletMapper;
import com.hang.gymmanager.req.AddActivityReq;
import com.hang.gymmanager.req.BuyActivityReq;
import com.hang.gymmanager.req.PageActivityReq;
import com.hang.gymmanager.req.UpdateActivityReq;
import com.hang.gymmanager.res.*;
import com.hang.gymmanager.service.*;
import com.hang.gymmanager.util.SecurityUtils;
import com.hang.gymmanager.util.SnowFlake;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.hang.gymmanager.Enum.CommonConstant.LINUX_PATH;

/**
 * @author wyq
 * @version v1.0.0
 * @explain
 * @date 2024/3/20 19:31
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ActivityServiceImpl extends ServiceImpl<ActivityMapper, ActivityEntity> implements ActivityService {

    private final PojoConvert pojoConvert;
    private final PlaceUseRecordService placeUseRecordService;
    private final SeatService seatService;

    private final WalletMapper walletMapper;

    private final OrderService orderService;

    private final SeatMapper seatMapper;
    private final UserInfoService userInfoService;




    @Override
    //添加事务确保一致性
    @Transactional(rollbackFor = Exception.class)
    public Integer addActivity(AddActivityReq req) {
        //做同日判断
        List<TimePeriodDto> dtos = req.getList();
        Set<LocalDate> collect = dtos.stream().map(TimePeriodDto::getDay).collect(Collectors.toSet());
        if(collect.size()>1){
            throw new BusinessException("活动只能支持同一天");
        }
        List<TimePeriodDto> list = req.getList();
        TimePeriodDto dto = checkTimeContinue(list);
        //先把活动信息插库
        ActivityEntity activityEntity = new ActivityEntity();
        activityEntity.setActivityName(req.getActivityName())
                .setStatus(ActivityStatusEnum.WAIT.getValue())
                .setCreateTime(LocalDateTime.now())
                .setCreateAdminId(SecurityUtils.getUserId())
                .setEndTime(LocalDateTime.of(dtos.get(0).getDay(),dto.getEndTime()))
                .setHostName(req.getHostName())
                .setImgPath(req.getImgPath())
                .setIntroduce(req.getIntroduce())
                .setStartTime(LocalDateTime.of(dtos.get(0).getDay(),dto.getStartTime()))
                .setIsDelete(0);
        this.save(activityEntity);
        //把场地占用关系表插入
        QueryWrapper<PlaceUseRecordEntity> useRecordWrapper = new QueryWrapper<>();
        useRecordWrapper.lambda().eq(PlaceUseRecordEntity::getDay,dtos.get(0).getDay())
                        .between(PlaceUseRecordEntity::getStartTime,dto.getStartTime(),dto.getEndTime())
                        .between(PlaceUseRecordEntity::getEndTime,dto.getStartTime(),dto.getEndTime());
        List<PlaceUseRecordEntity> list1 = placeUseRecordService.getBaseMapper().selectList(useRecordWrapper);
        list1.stream().forEach(e->{
            e.setType(PlaceUseRecordTypeEnum.ACTIVITY.getValue());
            e.setRelationId(activityEntity.getActivityId());
            e.setStatus(PlaceUseRecordStatusEnum.OCCUPY.getValue());
        });
        placeUseRecordService.saveOrUpdateBatch(list1);
        //0322加逻辑 把模板的座位数据复制一份，根据当前的活动信息直接加一份数据进去
        QueryWrapper<SeatEntity> seatWrapper = new QueryWrapper<>();
        seatWrapper.lambda().eq(SeatEntity::getActivityId,-1);
        List<SeatEntity> seatEntities = seatService.getBaseMapper().selectList(seatWrapper);
        seatEntities.stream().forEach(e->{
            e.setId(null);
            e.setActivityId(activityEntity.getActivityId());
            if(e.getType()== SeatTypeEnum.HIGH.getValue()){
                e.setPrice(req.getHighPrice());
            }else if(e.getType()== SeatTypeEnum.MID.getValue()){
                e.setPrice(req.getMidPrice());
            }else if(e.getType()== SeatTypeEnum.LOW.getValue()){
                e.setPrice(req.getLowPrice());
            }else {
                throw new BusinessException("数据库座位登记类型出错");
            }
        });
        seatService.saveBatch(seatEntities);
        return activityEntity.getActivityId();
    }

    @Override
    public Page<PageActivityRes> allActivity(PageActivityReq req) {
        Page page = new Page(req.getPageNum(),req.getPageSize());
        Page<PageActivityRes> info = this.getBaseMapper().allActivity(req,page);
        return info;
    }

    @Override
    public void deleteActivity(Integer activityId) {
        //先判断活动状态 只有未开始的时候才能删除
        QueryWrapper<ActivityEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ActivityEntity::getActivityId,activityId);
        ActivityEntity activityEntity = this.getBaseMapper().selectOne(wrapper);
        if(!activityEntity.getStatus().equals(ActivityStatusEnum.WAIT.getValue())){
            throw new BusinessException("当前活动处于进行中或者结束，不能删除活动");
        }
        QueryWrapper<SeatEntity> seatWrapper = new QueryWrapper<>();
        seatWrapper.lambda().eq(SeatEntity::getActivityId,activityId)
                .isNotNull(SeatEntity::getUserId);
        List<SeatEntity> seatEntities = seatService.getBaseMapper().selectList(seatWrapper);
        seatEntities.stream().forEach(e->{
            //先把订单退款
            OrderEntity entity = new OrderEntity();
            entity.setOrderId(e.getOrderId());
            entity.setStatus(OrderStatusEnum.REFUND.getValue());
            orderService.getBaseMapper().updateById(entity);
            //然后把余额还给用户
            WalletEntity walletEntity = walletMapper.selectById(e.getUserId());
            walletEntity.setBalance(walletEntity.getBalance().add(e.getPrice()));
            walletMapper.updateById(walletEntity);
        });
        //解除场地占用
        QueryWrapper<PlaceUseRecordEntity> placeUseWrapper = new QueryWrapper<>();
        placeUseWrapper.lambda().eq(PlaceUseRecordEntity::getType,PlaceUseRecordTypeEnum.ACTIVITY.getValue())
                .eq(PlaceUseRecordEntity::getRelationId,activityId);
        List<PlaceUseRecordEntity> placeUseRecordEntities = placeUseRecordService.getBaseMapper().selectList(placeUseWrapper);
        placeUseRecordEntities.stream().forEach(e->{
            e.setType(PlaceUseRecordTypeEnum.NONE.getValue());
            e.setRelationId(-1);
        });
        placeUseRecordService.saveOrUpdateBatch(placeUseRecordEntities);
        //删除座位
        seatWrapper.clear();
        seatWrapper.lambda().eq(SeatEntity::getActivityId,activityId);
        seatService.remove(seatWrapper);
        //最后删除活动
        activityEntity.setIsDelete(CommonEnum.YES.getValue());
        activityEntity.setStatus(ActivityStatusEnum.CANCEL.getValue());
        this.saveOrUpdate(activityEntity);
    }

    @Override
    public ActivityDetailRes detail(Integer actId) {
        //先查活动本体
        QueryWrapper<ActivityEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ActivityEntity::getActivityId,actId);
        ActivityEntity activityEntity = this.getBaseMapper().selectOne(wrapper);
        ActivityDetailRes res = new ActivityDetailRes();
        BeanUtils.copyProperties(activityEntity,res);
        //再查占用场地
        QueryWrapper<PlaceUseRecordEntity> useWrapper = new QueryWrapper<>();
        useWrapper.lambda().eq(PlaceUseRecordEntity::getType,PlaceUseRecordTypeEnum.ACTIVITY.getValue())
                .eq(PlaceUseRecordEntity::getRelationId,actId)
                .orderByAsc(PlaceUseRecordEntity::getPlaceId);
        List<PlaceUseRecordEntity> placeUseRecordEntities = placeUseRecordService.getBaseMapper().selectList(useWrapper);
        List<Integer> placeIds = placeUseRecordEntities.stream().map(PlaceUseRecordEntity::getPlaceId).collect(Collectors.toList());
        res.setPlaceIds(placeIds);
        List<ActSeatRes> resList = seatMapper.getSeat(actId);
        res.setSeats(resList);
        return res;
    }

    @Override
    public Page<UserPlacePageRes> userActivityPage(BasePageReq req) {
        //数量page
        Page page = new Page(req.getPageNum(),req.getPageSize());
        QueryWrapper<ActivityEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().orderByDesc(ActivityEntity::getCreateTime)
                .eq(ActivityEntity::getIsDelete,CommonEnum.NO.getValue())
                .orderByDesc(ActivityEntity::getStatus);
        Page info = this.getBaseMapper().selectPage(page,wrapper);
        List<UserPlacePageRes> list = pojoConvert.userActivityPageEntity2Res(info.getRecords());
        //这里没办法了必须要用convert;
        page.setRecords(list);
        return page;
    }

    /**
     * 用户查询活动信息
     * @param activityId
     * @return
     */
    @Override
    public UserActivityDetailRes userActivityDetail(Integer activityId) {
        //先查活动信息
        UserActivityDetailRes res = new UserActivityDetailRes();
        ActivityEntity activityEntity = this.getBaseMapper().selectById(activityId);
        res.setActivity(activityEntity);
        //查询座位信息
        List<UserSeatRes> resList = seatMapper.userSeatStatus(activityId);
        res.setSeat(resList);
        return res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized String buy(BuyActivityReq req) {
        Integer userId = SecurityUtils.getUserId();
        //创建订单id
        Snowflake snowflake = new Snowflake();
        long orderId = snowflake.nextId();
        //先查询用户的钱包余额是不是足够
        WalletEntity wallet = walletMapper.selectById(userId);
        BigDecimal balance = wallet.getBalance();
        if(balance.doubleValue()<req.getTotalPrice().doubleValue()){
            throw new BusinessException("账户余额不足");
        }
        StringBuffer message = new StringBuffer();
        //进行锁座
        if(req.getHigh()!=null&&req.getHigh()!=0){
            List<Map<String, Integer>> maps = seatService.lockSeat(req.getActivityId(),
                    orderId,
                    userId,
                    SeatTypeEnum.HIGH.getValue(),
                    req.getHigh());
            maps.stream().forEach(e->{
                message.append(e.get("area"))
                        .append("号场地")
                        .append(e.get("row"))
                        .append("排")
                        .append(e.get("column"))
                        .append("座")
                        .append(",");
            });
        }
        if(req.getMid()!=null&&req.getMid()!=0){
            List<Map<String, Integer>> maps = seatService.lockSeat(req.getActivityId(),
                    orderId,
                    userId,
                    SeatTypeEnum.MID.getValue(),
                    req.getMid());
            maps.stream().forEach(e->{
                message.append(e.get("area"))
                        .append("号场地")
                        .append(e.get("row"))
                        .append("排")
                        .append(e.get("column"))
                        .append("座")
                        .append(",");
            });
        }
        if(req.getLow()!=null&&req.getLow()!=0){
            List<Map<String, Integer>> maps = seatService.lockSeat(req.getActivityId(),
                    orderId,
                    userId,
                    SeatTypeEnum.LOW.getValue(),
                    req.getMid());
            maps.stream().forEach(e->{
                message.append(e.get("area"))
                        .append("号场地")
                        .append(e.get("row"))
                        .append("排")
                        .append(e.get("column"))
                        .append("座")
                        .append(",");
            });
        }
        //进行扣款
        wallet.setBalance(wallet.getBalance().subtract(req.getTotalPrice()));
        walletMapper.updateById(wallet);
        //订单插入
        UserInfoEntity userinfo = userInfoService.getBaseMapper().selectById(userId);
        //创建订单
        OrderEntity order = new OrderEntity();
        order.setStatus(OrderStatusEnum.PAYED.getValue())
                .setType(OrderTypeEnum.ACTIVITY.getValue())
                .setPrice(req.getTotalPrice())
                .setRelationId(req.getActivityId())
                .setCreateTime(LocalDateTime.now())
                .setUserId(userId)
                .setFinishTime(LocalDateTime.now())
                .setUserName(userinfo.getName())
                .setMessage(message.toString());
        orderService.save(order);
        //返回信息
        return message.toString();
    }

    @Override
    public List<AddActPlaceRes> placeRecord() {
        List<AddActPlaceRes> list = this.getBaseMapper().actPlaceRecord(LocalDate.now());
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadPic(MultipartFile file) {
        Integer userId = SecurityUtils.getUserId();
        //如果文件为空 报错
        if (file.isEmpty()) {
            throw new BusinessException("文件为空");
        }
        String fileName = null;
        try {
            //获取项目当前路径
//            String url = "D:\\ideaProject";
            String url = LINUX_PATH;
            Path imgPath = Paths.get(url,"img");
            //获取文件字节流文件
            byte[] bytes = file.getBytes();
            //文件id
            //文件id
            String randomString = UUID.randomUUID().toString();
            // 仅保留前 5 个字符作为随机字符串
            String newRan = randomString.substring(0, 5);
            fileName = newRan+"-"+ImgTypeEnum.ACTIVITY.getValue()+".jpg";
            // 构建保存文件的路径
            Path filePath = imgPath.resolve(fileName);
            // 将文件保存到本地
            Files.write(filePath, bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileName;
    }

    @Override
    public void updateActivity(UpdateActivityReq req) {
        ActivityEntity activityEntity = this.getById(req.getId());
        if(req.getActivityName()!=null&&!req.getActivityName().isEmpty()){
            activityEntity.setActivityName(req.getActivityName());
        }
        if(req.getHostName()!=null&&!req.getHostName().isEmpty()){
            activityEntity.setHostName(req.getHostName());
        }
        if(req.getImgPath()!=null&&!req.getImgPath().isEmpty()){
            activityEntity.setImgPath(req.getImgPath());
        }
        this.saveOrUpdate(activityEntity);
    }


    private TimePeriodDto checkTimeContinue(List<TimePeriodDto> list){
        if(list.size()==0){
            throw new BusinessException("未选择活动时间段");
        }
        if(list.size()==1){
           return list.get(0);
        }
        Collections.sort(list);
        for (int i = 0;i<=list.size()-2;i++){
            if(!list.get(i).getEndTime().equals(list.get(i+1).getStartTime())){
                throw new BusinessException("时间段不连续,请重试");
            }
        }
        TimePeriodDto dto = new TimePeriodDto();
        dto.setStartTime(list.get(0).getStartTime());
        dto.setEndTime(list.get(list.size()-1).getEndTime());
        return dto;
    }
}
